package com.jy.rhin.domain.notification.subscribe.entity;


import com.jy.rhin.domain.exception.RhinInfraErrorType;
import com.jy.rhin.domain.notification.subscribe.entity.vo.SubscribeTopicFilterVO;
import com.jy.rhin.infra.uitl.Asserts;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.time.DateFormatUtils;

import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.Random;

/**
 * @author WeiQ
 * @date 2022/6/28 9:55
 * 主题订阅信息
 */
@Slf4j
@Data
@NoArgsConstructor
public class SubscribeDO {

    private static final Random RANDOM = new Random();

    public SubscribeDO(String createBy) {
        this.createBy = createBy;
        this.createTime = new Date();
        this.subscribeUid = createUid();
    }

    public void updateSubscribeDefault(String subscribeUid, String createBy, Date createTime) {
        this.createBy = createBy;
        this.createTime = createTime;
        this.subscribeUid = subscribeUid;
    }

    /**
     * 订阅
     * 1、订阅者必须存在
     * 2、预存查询必须存在 且查询关联的主题与订阅主题相同
     *
     * @param id             订阅标识号
     * @param subscriberCode 订阅者代码
     * @param topicExp       订阅主题表达式
     * @param queryExp       使用的预存查询函数表达式
     * @param updateBy       操作人
     * @return
     */
    public SubscribeDO subscribe(Long id, String subscriberCode, String topicExp, String queryExp, String updateBy) {
        this.id = id;
        this.subscriberCode = subscriberCode;
        this.topicExp = topicExp;
        this.queryExp = queryExp;
        this.status = EnumSubscribeStatus.SUBSCRIBED;
        this.updateBy = updateBy;
        this.updateTime = new Date();
        return this;
    }

    /**
     * 验证是否接受更新: 更新订阅信息时，subscriberCode和topicId不能修改
     * 已取消状态的数据不能更新
     *
     * @return
     */
    public void accessUpdate(String subscriberCode, String topicExp) {
        Asserts.equals(this.subscriberCode, subscriberCode, RhinInfraErrorType.SUBSCRIBE_UPDATE_FIELD_ERROR);
        Asserts.equals(this.topicExp, topicExp, RhinInfraErrorType.SUBSCRIBE_UPDATE_FIELD_ERROR);
        Asserts.isFalse(Objects.equals(this.status, EnumSubscribeStatus.CANCEL), RhinInfraErrorType.SUBSCRIBE_STATUS_CANCEL_NOT_UPDATE);
    }

    /**
     * 取消订阅 已经取消的订阅，不能重复取消
     *
     * @param updateBy
     * @return
     */
    public boolean cancel(String updateBy) {
        if (this.status == EnumSubscribeStatus.CANCEL) {
            return false;
        }
        this.status = EnumSubscribeStatus.CANCEL;
        this.updateBy = updateBy;
        this.updateTime = new Date();
        return true;
    }

    /**
     * 暂停订阅 必须是订阅状态
     *
     * @param updateBy
     * @return
     */
    public boolean pause(String updateBy) {
        if (this.status != EnumSubscribeStatus.SUBSCRIBED) {
            return false;
        }
        this.status = EnumSubscribeStatus.PAUSED;
        this.updateBy = updateBy;
        this.updateTime = new Date();
        return true;
    }

    /**
     * 恢复订阅 必须是暂停订阅状态
     *
     * @return
     */
    public boolean resume(String updateBy) {
        if (this.status != EnumSubscribeStatus.PAUSED) {
            return false;
        }
        this.status = EnumSubscribeStatus.SUBSCRIBED;
        this.updateBy = updateBy;
        this.updateTime = new Date();
        return true;
    }

    /**
     * 年月日+随机数生成订阅标识号
     *
     * @return
     */
    private static String createUid() {
        int fot = RANDOM.nextInt(9000) + 1000;
        String head = DateFormatUtils.format(new Date(), "yyyyMMdd");
        return head + fot;
    }

    /**
     * 主键id
     */
    private Long id;
    /**
     * 订阅标识号
     */
    private String subscribeUid;
    /**
     * 订阅者代码
     */
    private String subscriberCode;
    /**
     * 订阅主题表达式
     */
    private String topicExp;
    /**
     * 使用的预存查询函数表达式
     */
    private String queryExp;
    /**
     * 订阅状态;SUBSCRIBED:已订阅, CANCEL:已取消,PAUSED:已暂停
     */
    private EnumSubscribeStatus status;

    /**
     * 过滤条件参数列表
     */
    private List<SubscribeTopicFilterVO> filterList;
    /**
     * 创建人
     */
    private String createBy;
    /**
     * 创建时间
     */
    private Date createTime;
    /**
     * 更新人
     */
    private String updateBy;
    /**
     * 更新时间
     */
    private Date updateTime;

}
